﻿#region Using

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Vk.Methods.Audios;
using Vk.Methods.Common;
using Vk.Methods.Friends;
using Vk.Methods.Photos;

#endregion

namespace Vk.Methods.Users
{
    /// <summary>
    ///     Минимальный набор данных о пользователе
    /// </summary>
    public class BaseUser
    {
        /// <summary>
        ///     Поле, содержащее строку "deleted" или "banned" в случае, если запрашиваемый аккаунт заблокирован или удален
        ///     владельцем.
        /// </summary>
        public string Deactivated { get; set; }

        /// <summary>
        ///     Имя
        /// </summary>
        public string FirstName { get; set; }

        /// <summary>
        ///     Если пользователь в настройках приватности скрыл свою страницу от неавторизованных в ВК посетителей, то true
        /// </summary>
        public bool? Hidden { get; set; }

        /// <summary>
        ///     Id пользователя
        /// </summary>
        public int? Id { get; set; }

        /// <summary>
        ///     Фамилия
        /// </summary>
        public string LastName { get; set; }

        public BaseUser(int? id)
        {
            Id = id;
        }

        public BaseUser(ApiNode node)
        {
            Id = node.Int("id");
            FirstName = node.String("first_name");
            LastName = node.String("last_name");

            Hidden = node.Bool("hidden");
            Deactivated = node.String("deactivated");
        }
    }

    /// <summary>
    ///     Пользователь ВК
    /// </summary>
    public class User : BaseUser
    {
        private readonly ApiNode _node;

        /// <summary>
        ///     Количество различных объектов у пользователя
        /// </summary>
        public UserCounters Counters
            =>
                _node.SelectNode(UserFields.Counters) != null
                    ? new UserCounters(_node.SelectNode(UserFields.Counters))
                    : null;

        /// <summary>
        ///     Информация о текущем роде занятия пользователя
        /// </summary>
        public UserOccupation Occupation => _node.Object(UserFields.Occupation, apiNode => new UserOccupation(apiNode));

        /// <summary>
        ///     Cписок родственников текущего пользователя.
        /// </summary>
        public List<IdTypeName<RelativeType>> Relatives
            => _node.SelectNode(UserFields.Relatives).ChildNodes.Select(x => new IdTypeName<RelativeType>(x)).ToList();

        public User(int? id) : base(id)
        {
        }

        public User(ApiNode node) : base(node)
        {
            //This node will be used for deferred data fetching
            _node = node;
        }

        public override string ToString()
        {
            return FirstName + " " + LastName;
        }

        #region Base

        /// <summary>
        ///     Пол
        /// </summary>
        public UserSex? Sex => (UserSex?) _node.Int(UserFields.Sex);

        /// <summary>
        /// Возвращает имя пользователя в заданном падеже. 
        /// </summary>
        /// <param name="nameCase">Падеж</param>
        public string FirstNameInCase(UserNameCase nameCase) => _node.String(UserFields.FirstNameInCase(nameCase));

        /// <summary>
        /// Возвращает фамилию пользователя в заданном падеже. 
        /// </summary>
        /// <param name="nameCase">Падеж</param>
        public string LastNameInCase(UserNameCase nameCase) => _node.String(UserFields.LastNameInCase(nameCase));

        /// <summary>
        /// Девичья фамилия.
        /// </summary>
        public string MaidenName => _node.String(UserFields.MaidenName);

        /// <summary>
        ///     Дата рождения
        /// </summary>
        public string BirthDate => _node.String(UserFields.BirthDate);

        /// <summary>
        ///     Id и Title города, в котором живет пользователь
        /// </summary>
        public IdTitleObject City => _node.Object(UserFields.City, apiNode => new IdTitleObject(apiNode));

        /// <summary>
        ///     Id и Title страны, в которой живет пользователь
        /// </summary>
        public IdTitleObject Country => _node.Object(UserFields.Country, apiNode => new IdTitleObject(apiNode));

        /// <summary>
        ///     Пользовательский домен. Например, vladrocklike
        /// </summary>
        public string Domain => _node.String(UserFields.Domain);

        /// <summary>
        ///     Никнейм (отчество) пользователя.
        /// </summary>
        public string Nickname => _node.String(UserFields.Nickname);

        /// <summary>
        ///     Короткое имя (поддомен) страницы пользователя.
        /// </summary>
        public string ScreenName => _node.String(UserFields.ScreenName);

        /// <summary>
        ///     Временная зона пользователя. Возвращается только при запросе информации о текущем пользователе.
        /// </summary>
        public short? Timezone => _node.Short(UserFields.Timezone);

        /// <summary>
        ///     Возвращается true, если текущий пользователь находится в черном списке у запрашиваемого.
        /// </summary>
        public bool? Blacklisted => _node.Bool(UserFields.Blacklisted);

        /// <summary>
        /// Информация о том, находится ли пользователь в черном списке у текущего пользователя. 
        /// </summary>
        public bool? BlacklistedByMe => _node.Bool(UserFields.BlacklistedByMe);

        /// <summary>
        ///     Название родного города пользователя
        /// </summary>
        public string Hometown => _node.String(UserFields.Hometown);

        /// <summary>
        ///     Количество подписчиков пользователя.
        /// </summary>
        public int? FollowersCount => _node.Int(UserFields.FollowersCount);

        /// <summary>
        ///     Количество общих друзей с текущим пользователем.
        /// </summary>
        public int? CommonCount => _node.Int(UserFields.CommonCount);

        #endregion

        #region Photo

        /// <summary>
        /// true, если текущий пользователь установил фотографию для профиля.
        /// </summary>
        public bool? HasPhoto => _node.Bool(UserFields.HasPhoto);

        /// <summary>
        /// Данные о точках, по которым вырезаны профильная и миниатюрная фотографии пользователя.
        /// </summary>
        public CropPhoto CropPhoto => _node.Object(UserFields.CropPhoto, apiNode => new CropPhoto(apiNode));

        /// <summary>
        ///     url квадратной фотографии пользователя, имеющей ширину 50 пикселей
        /// </summary>
        public string Photo50 => _node.String(UserFields.Photo50);

        /// <summary>
        ///     url квадратной фотографии пользователя, имеющей ширину 100 пикселей
        /// </summary>
        public string Photo100 => _node.String(UserFields.Photo100);

        /// <summary>
        ///     url фотографии пользователя, имеющей ширину 200 пикселей
        /// </summary>
        public string Photo200Orig => _node.String(UserFields.Photo200Orig);

        /// <summary>
        ///     url фотографии пользователя, имеющей ширину 400 пикселей. Если у пользователя отсутствует фотография такого
        ///     размера, ответ не будет содержать этого поля.
        /// </summary>
        public string Photo400Orig => _node.String(UserFields.Photo400Orig);

        /// <summary>
        ///     url квадратной фотографии пользователя, имеющей ширину 200 пикселей
        /// </summary>
        public string Photo200 => _node.String(UserFields.Photo200);

        /// <summary>
        ///     url квадратной фотографии пользователя с максимальной шириной
        /// </summary>
        public string PhotoMax => _node.String(UserFields.PhotoMax);

        /// <summary>
        ///     url фотографии пользователя максимального размера. Может быть возвращена фотография, имеющая ширину как 400, так и
        ///     200 пикселей
        /// </summary>
        public string PhotoMaxOrig => _node.String(UserFields.PhotoMaxOrig);

        /// <summary>
        /// Строковый идентификатор главной фотографии профиля пользователя в формате {user_id}_{photo_id}, например, 6492_192164258. В некоторых случаях (если фотография была установлена очень давно) это поле не возвращается.
        /// </summary>
        public string PhotoId => _node.String(UserFields.PhotoId);

        #endregion

        #region Status

        /// <summary>
        ///     Статус пользователя
        /// </summary>
        public string Status => _node.String(UserFields.Status);

        /// <summary>
        ///     Аудиозапись, которую слушает пользователь
        /// </summary>
        public Audio StatusAudio => _node.Object("status_audio", apiNode => new Audio(apiNode));

        //TODO: Online object with fields below (...Mobile, ...App)
        /// <summary>
        ///     Пользователь онлайн
        /// </summary>
        public bool? Online => _node.Bool(UserFields.Online);

        /// <summary>
        ///     Пользователь онлайн с мобильного телефона
        /// </summary>
        public bool? OnlineMobile => _node.Bool("online_mobile");

        /// <summary>
        ///     Идентификатор приложения, которое используется в данный момент
        /// </summary>
        public int? OnlineApp => _node.Int("online_app");

        /// <summary>
        ///     Время последнего посещения
        /// </summary>
        public DateTime? LastSeen => _node.DateTime(UserFields.LastSeen);

        /// <summary>
        ///     Семейное положение пользователя
        /// </summary>
        public UserMaritalStatus? Relation => (UserMaritalStatus?)_node.Int(UserFields.Relation);

        /// <summary>
        /// Cтатус дружбы с пользователем. 
        /// </summary>
        public FriendStatusEnum? FriendStatus => (FriendStatusEnum?)_node.Int(UserFields.FriendStatus);

        #endregion

        #region Education

        /// <summary>
        /// Информация о высшем учебном заведении пользователя. 
        /// </summary>
        public UserEducation Education => _node.Object(UserFields.Education, apiNode => new UserEducation(apiNode));

        /// <summary>
        ///     Список высших учебных заведений, в которых учился текущий пользователь.
        /// </summary>
        public List<University> Universities => _node.SelectNode(UserFields.Universities).ChildNodes.Select(x => new University(x)).ToList();

        /// <summary>
        ///     Список школ, в которых учился пользователь.
        /// </summary>
        public List<School> Schools
            => _node.SelectNode(UserFields.Schools).ChildNodes.Select(x => new School(x)).ToList();

        #endregion

        #region Contacts

        /// <summary>
        ///     Мобильный телефон доступен
        /// </summary>
        public bool? HasMobile => _node.Bool(UserFields.HasMobile);

        /// <summary>
        ///     Листы, в которые добавлен пользователь
        /// </summary>
        public List<int> Lists => _node.SelectNode(UserFields.Lists).ChildNodes.Select(x => x.Int().Value).ToList();

        /// <summary>
        ///     Указанный в профиле сайт пользователя
        /// </summary>
        public string Site => _node.String(UserFields.Site);

        #endregion

        #region Posibilities

        /// <summary>
        ///     Информация о том, разрешено ли оставлять записи на стене у пользователя
        /// </summary>
        public bool? CanPost => _node.Bool(UserFields.CanPost);

        /// <summary>
        ///     Информация о том, разрешено ли видеть чужие записи на стене пользователя
        /// </summary>
        public bool? CanSeeAllPosts => _node.Bool(UserFields.CanSeeAllPosts);

        /// <summary>
        ///     Информация о том, разрешено ли видеть чужие аудиозаписи на стене пользователя
        /// </summary>
        public bool? CanSeeAudio => _node.Bool(UserFields.CanSeeAudio);

        /// <summary>
        /// Информация о том, будет ли отправлено уведомление пользователю о заявке в друзья от текущего пользователя
        /// </summary>
        public bool? CanSendFriendRequest => _node.Bool(UserFields.CanSendFriendRequest);

        /// <summary>
        ///     Информация о том, разрешено ли написание личных сообщений данному пользователю
        /// </summary>
        public bool? CanWritePrivateMessage => _node.Bool(UserFields.CanWritePrivateMessage);

        /// <summary>
        ///     Доступно ли комментирование стены
        /// </summary>
        public bool? WallComments => _node.Bool(UserFields.WallComments);

        #endregion

        /// <summary>
        /// Информация о карьере пользователя.
        /// </summary>
        public UserCareer Career => _node.Object(UserFields.Career, apiNode => new UserCareer(apiNode));

        /// <summary>
        /// Данные об указанных в профиле сервисах пользователя.
        /// </summary>
        public UserConnections Connections => new UserConnections(_node);

        /// <summary>
        /// Информация о телефонных номерах пользователя.
        /// </summary>
        public UserContacts Contacts => _node.Object(UserFields.Contacts, apiNode => new UserContacts(apiNode));

        /// <summary>
        /// Информация о военной службе пользователя. 
        /// </summary>
        public UserMilitary Military => _node.Object(UserFields.Military, apiNode => new UserMilitary(apiNode));

        /// <summary>
        /// Информация о полях из раздела «Жизненная позиция».
        /// </summary>
        public UserPersonal Personal => _node.Object(UserFields.Personal, apiNode => new UserPersonal(apiNode));

        /// <summary>
        /// Возвращается true, если страница пользователя верифицирована, false — если не верифицирована.
        /// </summary>
        public bool? IsVerified => _node.Bool(UserFields.Verified);

        #region Info

        /// <summary>
        ///     Деятельность.
        /// </summary>
        public string Activities => _node.String(UserFields.Activities);

        /// <summary>
        ///     Интересы.
        /// </summary>
        public string Interests => _node.String(UserFields.Interests);

        /// <summary>
        ///     Любимая музыка.
        /// </summary>
        public string Music => _node.String(UserFields.Music);

        /// <summary>
        ///     Любимые фильмы.
        /// </summary>
        public string Movies => _node.String(UserFields.Movies);

        /// <summary>
        ///     Любимые шоу.
        /// </summary>
        public string Tv => _node.String(UserFields.TV);

        /// <summary>
        ///     Любимые книги.
        /// </summary>
        public string Books => _node.String(UserFields.Books);

        /// <summary>
        ///     Любимые игры.
        /// </summary>
        public string Games => _node.String(UserFields.Games);

        /// <summary>
        ///     "О себе".
        /// </summary>
        public string About => _node.String(UserFields.About);

        /// <summary>
        ///     Любимые цитаты.
        /// </summary>
        public string Quotes => _node.String(UserFields.Quotes);

        #endregion

        /// <summary>
        /// Информация о том, есть ли пользователь в закладках у текущего пользователя.
        /// </summary>
        public bool? IsFavorite => _node.Bool(UserFields.IsFavorite);

        /// <summary>
        /// Информация о том, является ли пользователем другом текущего пользователя. 
        /// </summary>
        public bool? IsFriend => _node.Bool(UserFields.IsFriend);

        /// <summary>
        /// Информация о том, скрыт ли пользователь из ленты новостей текущего пользователя.
        /// </summary>
        public bool? IsHiddenFromFeed => _node.Bool(UserFields.IsHiddenFromFeed);
    }
}